package com.seadragon.app.ksr.loader;

import static com.seadragon.app.ksr.loader.StateLoader.appCtx;
import static com.seadragon.app.ksr.model.KsrConstants.gf;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.seadragon.app.ksr.model.SHPFileRecord;
import com.seadragon.app.ksr.model.shape.PolygonShape;
import com.seadragon.app.ksr.model.tiger.County;
import com.seadragon.app.ksr.model.tiger.Zip;
import com.seadragon.app.ksr.service.SearchService;
import com.seadragon.app.ksr.util.FileUtils;
import com.seadragon.app.ksr.util.IndexManager;
import com.seadragon.app.ksr.util.tiger.DBFFileReader;
import com.seadragon.app.ksr.util.tiger.SHPFileReader;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Polygon;

@Component("zipLoader")
public class ZipLoader {

	private static Logger logger = LoggerFactory.getLogger(ZipLoader.class);
	private static final String SHP_FILE_EXTENSION = ".shp";
	private static final String DBF_FILE_EXTENSION = ".dbf";
	@Autowired
	private IndexManager indexManager;
	@Autowired
	private SearchService searchService;
	private static final String WORK_FOLDER = "work";
	private DBFFileReader dbfFileReader;
	private SHPFileReader shpFileReader;
	
	private int from;
	private String data;
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		int from = 0;
		String data = null;
		for(int i = 0; i < args.length; i++){
			if(args[i].equalsIgnoreCase("-from")){
				from  = Integer.parseInt(args[++i]);
			}else if(args[i].equalsIgnoreCase("-data")){
				data = args[++i];
			}
		}
		ZipLoader loader = (ZipLoader) appCtx.getBean("zipLoader");
		loader.setFrom(from);
		loader.setData(data);
		logger.debug("Start to load " + args[0]);
		File workFolder = new File(WORK_FOLDER);
		try{
		loader.load(workFolder, FileUtils.getBaseName("tl_2013_us_zcta510.shp"));
		}catch(Exception ex){
			logger.error(ex.getMessage(), ex);
		}
//		byte[] buffer = new byte[1024];
//		File file = new File(args[0]);
//		if (!file.exists()) {
//			logger.error("File doesn't exist: " + args[0]);
//			return;
//		}
//		if (!file.isDirectory()) {
//			logger.error("This is not a directory: " + args[0]);
//			return;
//		}
//		File[] files = file.listFiles();
//		File workFolder = new File(WORK_FOLDER);
//		if (workFolder.exists()) {
//			for (File f : workFolder.listFiles()) {
//				f.delete();
//			}
//		} else {
//			workFolder.mkdir();
//		}
//
//		for (int i = 0; i < files.length; i++) {
//			try {
//				ZipInputStream zis = new ZipInputStream(new FileInputStream(files[i]));
//				// get the zipped file list entry
//				ZipEntry ze = zis.getNextEntry();
//				// All the files have the same base name
//				String fileName = null;
//				while (ze != null) {
//					fileName = ze.getName();
//					File newFile = new File(workFolder + File.separator + fileName);
//
//					// System.out.println("file unzip : " +
//					// newFile.getAbsoluteFile());
//
//					// create all non exists folders
//					// else you will hit FileNotFoundException for compressed
//					// folder
//					new File(newFile.getParent()).mkdirs();
//
//					FileOutputStream fos = new FileOutputStream(newFile);
//
//					int len;
//					while ((len = zis.read(buffer)) > 0) {
//						fos.write(buffer, 0, len);
//					}
//					fos.close();
//					ze = zis.getNextEntry();
//				}
//				zis.closeEntry();
//				zis.close();
//				loader.load(workFolder, FileUtils.getBaseName(fileName));
//			} catch (FileNotFoundException ex) {
//				logger.error(ex.getMessage(), ex);
//			} catch (IOException ex) {
//				logger.error(ex.getMessage(), ex);
//			}
//		}
	}

	public int getFrom() {
		return from;
	}

	public void setFrom(int from) {
		this.from = from;
	}

	public String getData() {
		return data;
	}

	public void setData(String data) {
		this.data = data;
	}

	public void load(File directory, String baseName) throws FileNotFoundException, IOException {
		dbfFileReader = new DBFFileReader(new File(directory + File.separator + baseName + DBF_FILE_EXTENSION));
		shpFileReader = new SHPFileReader(new File(directory + File.separator + baseName + SHP_FILE_EXTENSION));
		logger.info("Processing " + directory + File.separator + baseName + DBF_FILE_EXTENSION);
		int count = 0;
		while (dbfFileReader.hasNext() && shpFileReader.hasNext()) {
			List<Object> dbfRecord = dbfFileReader.next();
			SHPFileRecord shpRecord = shpFileReader.next();
			if(count++ < from) continue;
			Zip zip = new Zip();
			int index = 0;
			zip.setZip((String) dbfRecord.get(index++));
			zip.setGeoid((String) dbfRecord.get(index));
			index += 3;
			zip.setFuncStat((String) dbfRecord.get(index));
			index += 3;
			double lat = Double.parseDouble((String) dbfRecord.get(index++));
			double lng = Double.parseDouble((String) dbfRecord.get(index++));
			Coordinate coor = new Coordinate(lng, lat);
			zip.setIntpt(gf.createPoint(coor));
			Polygon[] polygons = new Polygon[shpRecord.getRecordContent().getNumOfParts()];
			PolygonShape ps = (PolygonShape)shpRecord.getRecordContent();

			for(int i = 0; i < polygons.length; i++){
				if(i == polygons.length - 1){
					polygons[i] = gf.createPolygon(Arrays.copyOfRange(ps.getPoints(), shpRecord.getRecordContent().getParts()[i], ps.getPoints().length));
				}else{
					polygons[i] = gf.createPolygon(Arrays.copyOfRange(ps.getPoints(), shpRecord.getRecordContent().getParts()[i], shpRecord.getRecordContent().getParts()[i+1]));
				}
			}
			County county = searchService.searchCountyByLocation(coor.y, coor.x);
			if(county != null){
				zip.setState(county.getState());
				zip.setCounty(county.getName());
			}
			zip.setGeom(gf.createMultiPolygon(polygons));
			try{
				indexManager.insertDocument(zip);
			}catch(Exception ex){
				logger.error(ex.getMessage(), ex);
			}
			logger.info(count + ": " + zip.getZip());

		}
		dbfFileReader.close();
		shpFileReader.close();
	}
}
